/*
 * @Descripttion: 自定义promise函数 IIFE  es5 立即执行函数 声明一个函数并立马执行
 * @version: 
 * @Author: Zuo
 * @Date: 2021-08-03 10:37:20
 * @LastEditors: Zuo
 * @LastEditTime: 2021-08-04 11:24:38
 */
(function(window){


    class Promise{
         /*
        Promise构造函数
        excutor:执行器函数（同步函数）
        */
        constructor(excutor){
            let self = this;  //将当前promise对象保存起来
            self.status = 'pending'  //给promise对象指定status属性。初始值pending
            self.data = undefined  // 给promise对象指定一个用于存储结果数据的属性
            self.callbacks = []   //每个元素结构：{onResolved(){},onRejected(){}}
            function resolve(value){
                if(self.status != 'pending'){
                    return
                }
                //将状态给为resolved
                self.status = 'resolved'  
                //保存value数据
                self.data = value 
                //如果有待执行的callback函数， 异步执行回调onResolved
                if(self.callbacks.length >0 ){
                setTimeout(()=>{
                    self.callbacks.forEach(callbacksObj =>{
                        callbacksObj.onResolved(value)
                    })
                })
                }
            }
            function reject(reason){
                if(self.status != 'pending'){
                    return
                }
                //将状态给为rejected
                self.status = 'rejected'  
                //保存value数据
                self.data = reason 
                //如果有待执行的callback函数， 异步执行回调函数里的OnRejected
                if(self.callbacks.length >0 ){
                    setTimeout(()=>{
                        self.callbacks.forEach(callbacksObj =>{
                            callbacksObj.onRejected(reason)
                        })
                    })
                }
            }
            //立即执行函数
            try{
                excutor(resolve,reject)
            }catch(errpr){  //如果执行器抛出异常，promise对象变成了rejected
                reject(error)
            }

        }

                /**
         * Promise 原型 对象 的 then()
         * 指定成功和失败的回调函数
         * 返回一个新的promise对象
         * 返回的promise结果由onResolved/onRejected执行结果决定
         */
        then (onResolved,onRejected){
            //如果then里没有传入成功回调 指定一个默认的成功回调 。 并且把value
            onResolved = typeof onResolved === 'function' ? onResolved : value => value

            //如果then里没有传入失败回调 指定一个默认的失败回调 。 并且把reason抛出 (实现错误/异常穿透的关键点)
            onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}  

            const self = this;

            // 返回一个新的promise对象
            return new Promise((resolve,reject)=>{
                /**
                 * 调用指定函数处理，根据执行结果改变这个return的promise状态
                 * @param {} callback 
                 */
                function handle(callback){
    /*
                        1.如果抛出异常，return的promise就会失败，reason就是error
                        2.如果回调函数返回不是promise，return的promise就会成功，value就是返回的值。
                        3.如果回调函数返回的是promise，return的promise结果就是这个promise的结果。
                        */
                        try{
                            const result = callback(self.data)
                            if(result instanceof Promise){
                            // 3.如果回调函数返回的是promise，return的promise结果就是这个promise的结果。
                            //  result.then(
                            //      value => resolve(value), 
                            //      reason => reject(reason)
                            //  )
    
                            result.then(resolve,reject)  //简写
    
                            /**
                             * 例子解释
                             */
    
                            // function fn (e){
                                
                            // }
                            // div.onclick = function(e){
                            //     fn(e)
                            // }
    
                            // div.onclick = fn
                            }else{
                            //2.如果回调函数返回不是promise，return的promise就会成功，value就是返回的值。
                            resolve(result)
                            }
                        }catch(error){
                        // 1.如果抛出异常，return的promise就会失败，reason就是error
                            reject(error)
                        }
                }
                
                //当前状态还是pending状态，将回调函数保存起来
                if(self.status == 'pending'){
                    self.callbacks.push({
                        onResolved(){
                            handle(onResolved)
                        },
                        onRejected(){
                            handle(onRejected)
                        }
                    })
                }else if(self.status === 'resolved'){  //当前是resolved状态，异步执行 onResolved 并改变return的promise状态
                    setTimeout(()=>{
                        handle(onResolved)
                    })
                }else {
                    //rejected
                    setTimeout(()=>{   //当前是rejected状态，异步执行 onResolved 并改变return的promise状态
                        handle(onRejected)
                    })
                }
            })
            
        }
        /**
         * Promise 原型 对象 的 catch()
         * 指定失败的回调函数
         * 返回一个新的promise对象
         */
        //这是直接在实例对象里
        catch (onRejected){
            return this.then(undefined,onRejected)
        }

        /**
         * Promised函数对象的方法resolve
         * 返回指定结果的成功的promise对象
         */
        // 给类添加方法 加static  
       static resolve = function(value){
            //返回成功/失败的promise
            return new Promise((resolve,reject)=>{
                // value是promise 使用value里的promise结果 作为结果。 
                if(value instanceof Promise){  
                    value.then(resolve,reject);
                }else{
                    //value不是promise promise变成成功 数据是value
                    resolve(value)
                }
            })
        }

        /**
         * Promised函数对象的方法reject
         *  返回指定reason的失败的promise对象
         */
         static reject = function(reason){
            //返回失败的promise
            return new Promise((_,reject)=>{
                reject(reason)
            })
        }

        /**
         * Promised函数对象的方法all  接收的数组
         * 返回一个promise，只有当所有promise都成功才成功，有一个失败就算失败
         */
         static all = function(promises){
            const values = new Array(promises.length) // 用来保存所有成功的value数组
            let resloveCount  = 0;  //记录成功的异步操作进入几次
            return new Promise((resolve,reject)=>{
                //遍历获取每个promise的结果
                promises.forEach((p,index)=>{
                Promise.resolve(p).then(value=>{ // p成功 保存在values里
                        values[index] = value
                        resloveCount ++
                        //如果全部成功了。 调用resolve 传入values
                        if(resloveCount == promises.length){
                            resolve(values);
                        }
                    },
                    reason =>{  //有一个失败 就return 一个失败
                        reject(reason)
                    }
                    )
                })
            })
        }


        /**
         * Promised函数对象的方法race  接收数组
         * 返回一个promise，其结果由第一个完成的promise决定
         */
         static race = function(promises){
        return new Promise((resolve,reject)=>{
                //遍历获取每个promise的结果
                promises.forEach((p)=>{
                    // p 可能不是一个promise，需要用Promise.reslove（p） 包装一下 变成一个promise对象。 不影响其原本的值
                    Promise.resolve(p).then(value=>{ // 有一个成功  就return 一个成功
                        resolve(value) 
                    },
                    reason =>{  //有一个失败 就return 一个失败
                        reject(reason)
                    }
                    )
                })
            })
        }

        /**
         * 返回一个promise对象，它在指定的时间后才确定结果
         */
         static resolveDelay = function (value ,time){
            //返回成功/失败的promise
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    // value是promise 使用value里的promise结果 作为结果。 
                    if(value instanceof Promise){  
                        value.then(resolve,reject);
                    }else{
                        //value不是promise promise变成成功 数据是value
                        resolve(value)
                    }
                },time)
            })
        }

        /**
         * 返回一个promise对象，它在指定的时间后才失败
         */
         static rejectDelay = function (reason ,time){
            //返回失败的promise
            return new Promise((_,reject)=>{
                setTimeout(()=>{
                    reject(reason)
                },time)
            })
        }

    }



    //向外暴露promise
    window.Promise = Promise
})(window)